#include <iostream>
#include <string.h>
#include <cassert>
using std::cout;
using std::endl;
using std::ostream;

class cow_string{

friend ostream& operator<<(ostream& os, const cow_string& rhs);

// no type named 'char_proxy' in 'cow_string'
// 放在前面会识别不了proxy
// friend ostream& operator<<(ostream& os, const cow_string::char_proxy& rhs); 

public:
    // 构造函数与析构函数
    cow_string();
    cow_string(const char* pstr);                   // 使用场景 s1 = "hello"
    ~cow_string();

    // 常见操作
    cow_string(const cow_string& rhs);              // 浅拷贝
//    cow_string(cow_string&& rhs);                   // 浅拷贝
    cow_string& operator=(const cow_string& rhs);   // 字符串赋值，使用场景 s2 = s1;
//    cow_string& operator=(cow_string&& rhs);        // 字符串赋值，使用场景 s2 = s1;
    char& operator[](size_t index);                 // 下标运算符，使用场景 char c = s[0];
    char operator[](size_t index) const;

    // 辅助函数
    const char* c_str() const;
    //operator char() const;

private:
    class char_proxy;
    char* _pstr;

// 这个友元声明必须在char_proxy后,才能看到char_proxy
friend ostream& operator<<(ostream& os, const cow_string::char_proxy& rhs); 
};

// 嵌套类
class cow_string::char_proxy{

friend ostream& operator<<(ostream& os, const cow_string::char_proxy& rhs);
public:
    // 构造函数
    char_proxy(cow_string& cow_str, size_t index);
    
    // 赋值函数
    char& operator=(const char& rhs);         // 使用场景 s1[0] = "H"

private:
    cow_string &_self;
    size_t _index;
};

cow_string::cow_string()
//    :_pstr(new char[sizeof(int) +1]() - 1){   // 往后偏移4位到int后
//        _pstr() - 4 = 1;
    :_pstr(new char[sizeof(int) + 1]() + sizeof(int)){
       *(int*)(_pstr - 4) = 1; 
    }

// 注意参数不是(const cow_string *rhs)
// 出现expected unqualified-id，很可能是没有加cow_string
cow_string::cow_string(const char* pstr)
    :_pstr(new char[sizeof(int) + strlen(pstr) + 1]() + sizeof(int)){
        strcpy(_pstr, pstr);    // 啊，总是忘了写这一步！
        *(int*)(_pstr - 4) = 1;
    }

// 每次对象析构时都会-1，直到==0为止才会释放内存
// 指针可能复用的情况需置空，全局资源必须置空
cow_string::~cow_string(){
    if(--*(int*)(_pstr - 4) == 0){
        delete[] (_pstr - 4);
        _pstr = nullptr;    // 记得置空指针
    }
}

//cow_string::cow_string(const cow_string& rhs)
//    :_pstr(new char[sizeof(int) + strlen(rhs._pstr) + 1]() + sizeof(int)){
//        strcpy(_pstr, rhs._pstr);   // 此处深拷贝，违反了共享原则
//        *(int*)(_pstr - 4) = 1;
//    }

cow_string::cow_string(const cow_string& rhs)
    :_pstr(rhs._pstr){
        ++*(int*)(_pstr - 4);
    }

// 记得返回引用
cow_string& cow_string::operator=(const cow_string& rhs){
    if(this != &rhs){
        //delete []_pstr;   // 记得减掉引用
        //delete [](_pstr - 4);   // 右边的引用可能不一定减到1，此处不一定删除字符串

        //if(--*(int*)(_pstr) == 0){
        if(--*(int*)(_pstr - 4) == 0){
            delete [](_pstr - 4);
        }

        _pstr = rhs._pstr;
        ++*(int*)(_pstr - 4);
    }

    return *this;
}

char& cow_string::operator[](size_t index){
//    return _pstr[index];     // 不能这样写，需要按照修改考虑！
    if(index >= strlen(_pstr)){
        throw std::out_of_range("cow_string::operator[] index out of range");
    }

    if(*(int*)(_pstr - 4) > 1){
        --*(int *)(_pstr - 4);
        char* temp = new char[strlen(_pstr) + 1 + 4]() + 4;
        strcpy(temp, _pstr);
         _pstr = temp;
        *(int *)(_pstr - 4) = 1;
    }

    return _pstr[index];
}

char cow_string::operator[](size_t index) const{
    // 越界检查
    if(index >= strlen(_pstr)){
        throw std::out_of_range("cow_string::operator[] index out of range");
    }

    return _pstr[index];
}

const char* cow_string::c_str() const{
    return _pstr;
}

ostream& operator<<(ostream& os, const cow_string& rhs){
   os << rhs._pstr;    
   // '_pstr' is a private member of 'cow_string'
   // 写friend, 可以写在最上面
    

    return os;
}

// 套娃式写法，能不报错真的是不容易啊
cow_string::char_proxy::char_proxy(cow_string & cow_str, size_t index)
// constructor for 'cow_string::char_proxy' must explicitly initialize the reference member '_self'
// 必须在初始化列表中初始化引用成员
// 让 char_proxy 对象能够安全地访问和修改所属的 cow_string 的内容
    :_self(cow_str)
    ,_index(index){

}

// 'char_proxy' is a private member of 'cow_string'
// 在 C++ 中，类的私有成员只能被该类的成员函数或友元（friend）访问
// 将 operator<< 声明为 cow_string 的友元函数
ostream& operator<<(ostream& os, const cow_string::char_proxy& rhs){
    
// '_self' is a private member of 'cow_string::char_proxy'
// 将该函数声明为char_proxy的友元
    os << rhs._self;
    //os << rhs._self._pstr[rhs._index];
    // no member named '_self' in 'cow_string'
    // 此时char_proxy需要前向声明
    return os;
}

char& cow_string::char_proxy::operator=(const char& rhs){
    // 越界检查
    if(_index >= strlen(_self._pstr)){
        throw std::out_of_range("cow_string::operator[] index out of range");
    }

    cout << "line 161: " << *(int*)(_self._pstr - 4) << endl;
    if(_self._pstr[_index] != rhs){
        if(*(int*)(_self._pstr - 4) > 1){
            --*(int*)(_self._pstr - 4);
            
            cout << "line 166: " << *(int*)(_self._pstr - 4) << endl;
            char *temp = new char[strlen(_self._pstr) + 4 + 1]() + 4;
            strcpy(temp, _self._pstr);

            _self._pstr = temp;
            *(int *)(_self._pstr - 4) = 1;
        }
    }

    _self._pstr[_index] = rhs;

    return _self._pstr[_index];
}

void test_cow_string() {
    // ==================== 基础构造测试 ====================
    cow_string s1("Hello");
    assert(strcmp(s1.c_str(), "Hello") == 0);
    std::cout << "1. 基础构造测试通过" << std::endl;

    // ==================== 拷贝构造测试 ====================
    cow_string s2 = s1;  // 拷贝构造
    assert(*(int*)(s1.c_str() - 4) == 2);  // 引用计数=2
    assert(strcmp(s2.c_str(), "Hello") == 0);
    std::cout << "2. 拷贝构造测试通过" << std::endl;

    // ==================== 写时复制(COW)测试 ====================
    s2[0] = 'h';  // 应触发COW
    //cout << *(int*)(s1.c_str() - 4) << '\n';
    //cout << *(int*)(s2.c_str() - 4) << '\n';
    assert(*(int*)(s1.c_str() - 4) == 1);  // s1引用计数降为1
    assert(*(int*)(s2.c_str() - 4) == 1);  // s2引用计数为1（新内存）
    assert(strcmp(s1.c_str(), "Hello") == 0);  // s1不变
    assert(strcmp(s2.c_str(), "hello") == 0);  // s2已修改
    std::cout << "3. 写时复制测试通过" << std::endl;

    // ==================== 赋值运算符测试 ====================
    cow_string s3;
    s3 = s1;  // 赋值操作
    assert(*(int*)(s1.c_str() - 4) == 2);  // 引用计数=2
    assert(strcmp(s3.c_str(), "Hello") == 0);
    std::cout << "4. 赋值运算符测试通过" << std::endl;

    // ==================== 下标访问测试 ====================
    assert(s3[1] == 'e');
    s3[1] = 'a';  // 修改字符
    assert(strcmp(s3.c_str(), "Hallo") == 0);
    assert(*(int*)(s1.c_str() - 4) == 1);  // s1引用计数因COW降为1
    std::cout << "5. 下标访问测试通过" << std::endl;

    // ==================== 引用计数测试 ====================
    {
        cow_string s4 = s1;
        assert(*(int*)(s1.c_str() - 4) == 2);
    }  // s4析构后
    assert(*(int*)(s1.c_str() - 4) == 1);  // s1引用计数恢复1
    std::cout << "6. 引用计数测试通过" << std::endl;

    // ==================== 异常测试 ====================
    try {
        s1[10] = '!';  // 越界访问
        assert(false);  // 不应执行到此处
    } catch (const std::out_of_range& e) {
        assert(strstr(e.what(), "out of range") != nullptr);
        std::cout << "7. 异常测试通过: " << e.what() << std::endl;
    }
}

void test_refcount_edge_cases() {
    // ==================== 自赋值测试 ====================
    cow_string s1("SelfAssign");
    int* refcount = (int*)(s1.c_str() - 4);
    int old_ref = *refcount;
    s1 = s1;  // 自赋值
    assert(*refcount == old_ref);  // 引用计数不应变化
    std::cout << "8. 自赋值测试通过" << std::endl;

    // ==================== 链式赋值测试 ====================
    cow_string s2("Chain1"), s3("Chain2"), s4("Chain3");
    s4 = s3 = s2;  // 链式赋值
    assert(*(int*)(s2.c_str() - 4) == 3);
    std::cout << "9. 链式赋值测试通过" << std::endl;

    // ==================== 空字符串赋值测试 ====================
    cow_string s5;
    cow_string s6("NonEmpty");
    s6 = s5;  // 空字符串赋值
    assert(*(int*)(s5.c_str() - 4) == 2);
    assert(strlen(s6.c_str()) == 0);
    std::cout << "10. 空字符串赋值测试通过" << std::endl;

    // ==================== 引用计数穿透测试 ====================
    cow_string s7("Source");
    cow_string s8 = s7;
    {
        cow_string s9 = s7;
        assert(*(int*)(s7.c_str() - 4) == 3);
    }
    // s9析构后
    assert(*(int*)(s7.c_str() - 4) == 2);  // 检查s7/s8计数是否正常
    s7[0] = 's';  // 触发COW
    assert(*(int*)(s7.c_str() - 4) == 1);
    assert(*(int*)(s8.c_str() - 4) == 1);  // s8应保持独立
    std::cout << "11. 引用计数穿透测试通过" << std::endl;

    // ==================== 移动语义模拟测试 ====================
//    cow_string s10("MoveSource");
//    cow_string s11 = std::move(s10);  // 模拟移动构造
//    assert(s10.c_str() != nullptr);    // 你的实现应保持源对象有效
//    assert(*(int*)(s11.c_str() - 4) == 1);
//    std::cout << "12. 移动语义模拟测试通过" << std::endl;
}

void test_char_proxy() {
    // ==================== 隐式转换测试 ====================
    cow_string s("Test");
    int* refcount = (int*)(s.c_str() - 4);
    int original_ref = *refcount;
    
    char c = s[0];  // 读取操作不应改变引用计数
    assert(c == 'T');
    assert(*refcount == original_ref); // 关键断言
    std::cout << "13. 隐式转换测试通过" << std::endl;

    // ==================== 连续赋值测试 ====================
    cow_string s2("Hello");
    cow_string s2_copy = s2; // 构造副本使引用计数=2
    
    s2[0] = s2[1] = 'X';  // 链式赋值应触发COW
    assert(strcmp(s2.c_str(), "XXllo") == 0);
    assert(*(int*)(s2_copy.c_str() - 4) == 1); // 原副本计数应降为1
    assert(*(int*)(s2.c_str() - 4) == 1);      // 新副本计数=1
    std::cout << "14. 连续赋值测试通过" << std::endl;

    // ==================== 只读引用测试 ====================
    const cow_string s3("Const");
    cow_string s3_copy = s3; // 引用计数=2
    
    char c2 = s3[0];  // const访问不应改变计数
    assert(c2 == 'C');
    assert(*(int*)(s3.c_str() - 4) == 2); // 关键断言
    std::cout << "15. 只读引用测试通过" << std::endl;

    // ==================== 新增：写操作计数测试 ====================
    cow_string s4("CountCheck");
    cow_string s4_ref = s4; // 引用计数=2
    
    s4[0] = 'C'; // 写操作应触发COW
    assert(*(int*)(s4_ref.c_str() - 4) == 1); // 原引用计数-1
    assert(*(int*)(s4.c_str() - 4) == 1);     // 新副本计数=1
    assert(s4[0] == 'C'); // 验证修改生效
    std::cout << "16. 写操作计数测试通过" << std::endl;

    // ==================== 新增：临时proxy生命周期测试 ====================
    cow_string s5("TempCheck");
    int* s5_refcount = (int*)(s5.c_str() - 4);
    {
        char proxy = s5[0];      // 临时proxy对象
        char c3 = proxy;         // 读取操作
        assert(*s5_refcount == 1); // 未修改时计数不变
    } // proxy析构
    assert(*s5_refcount == 1);    // proxy析构不应影响计数
    std::cout << "17. 临时proxy生命周期测试通过" << std::endl;
    // =================== 自增：查看查询字符 ====================
    cow_string s6("Hello");
    assert(*(int*)(s6.c_str() - 4) == 1);     // 新副本计数=1
    s6[0];  // 关键是修改会有带 = 的操作，因此需要重载运算符
    assert(*(int*)(s6.c_str() - 4) == 1);     // 新副本计数=1
    std::cout << "18. 下标不会自减的检测通过" << std::endl;
}

int main() {
    test_cow_string();
    std::cout << "===== 所有测试通过 =====" << std::endl;
    test_refcount_edge_cases(); 
    std::cout << "===== 所有测试通过 =====" << std::endl;
    test_char_proxy();
    std::cout << "===== 所有测试通过 =====" << std::endl;
    return 0;
}
